■ Sleep Mode スリープイン & ウェイク
<試作品仕様>
・ ボタンスイッチを押したらLEDが点滅して Sleep Mode に入る。
・ ボタンスイッチをおしたらウェイクする。
<試作品回路図>(→回路図のPDFファイル)
PIC18F87K90をつかった場合の回路図を以下に示します。

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています
<プログラム例>
#include <stdio.h>
#include <delays.h>
#pragma config FOSC = XT
#pragma config XINST = OFF
#pragma config WDTEN = OFF
int PowerMode;
void int0_RB0(void);
void delay_ms (long int cycle)
{
unsigned long int i = 0;
for (i = 0; i < cycle; i++)Delay10TCYx(25); // Delay10TCY():40μsec
}
#pragma code low_vector=0x8 //
void low_interrupt (void)
{
_asm GOTO int0_RB0 _endasm
}
#pragma code
#pragma interruptlow int0_RB0
void int0_RB0()
{
int i;
INTCONbits.INT0IF = 0;
delay_ms(50);
if(PORTBbits.RB0 == 0) //RB0ポートをチェックして0なら
{
for(i = 0; i < 4; i++) // 4 times Flicker
{
LATJbits.LATJ0 = 0; //LED ON
delay_ms(500); //500msec delay
LATJbits.LATJ0 = 1; //LED OFF
delay_ms(500); // 500msec
}
delay_ms(5000);
OSCCON = 0 ; //OSCCON Resiter
Sleep();
}
}
void main (void)
{
TRISA = 0;
TRISB = 0;
TRISBbits.TRISB0 = 1; //RB0/INT0 input Mode
TRISC = 0;
TRISD = 0;
TRISE = 0;
TRISF = 0;
TRISG = 0;
TRISH = 0;
TRISJ = 0;
//空きポートを0vにすると消費電流が低減します。
LATA = 0;
LATBbits.LATB1 = 0;
LATBbits.LATB2 = 0;
LATBbits.LATB3 = 0;
LATBbits.LATB4 = 0;
LATBbits.LATB5 = 0;
LATBbits.LATB6 = 0;
LATBbits.LATB7 = 0;
LATC = 0;
LATD = 0;
LATE = 0;
LATF = 0;
LATG = 0;
LATGbits.LATG2 = 1;
LATGbits.LATG3 = 1;
LATH = 0;
INTCON2bits.INTEDG0 = 0; //INT0 up rising detect
RCONbits.IPEN = 0; //interrupt priority NO
INTCONbits.INT0IE= 1; //INT0 Enable
INTCONbits.PEIE =1; //
INTCONbits.GIE = 1; //
while (1)
{
}
}
<動作結果>
・消費電流は 0.0μAでした。 手持ちの電流計(テスター: 秋月電子:METEX P-10)の最少測定限界が 0.1μAであることから 0.1μA以下を確認しました。
尚、マイクロチップのPIC18F87K90のデータシートには下記の値が記載されています。
Power-Down Current : 60nA(Type) at Sleep Mode、 25℃、 Vdd = 3.3v、 Regulator:: disabled、 ENVREG
= 0, Tied to Vss, RETEN (CONFIG1L<1>) = 1

■ スリープモードのSOSCに対する、ウォッチドックタイマの監視
通常、スリープモードの場合 WDTなども含め全クロックが停止させます。 したがって WDTをクリアする必要はありません。 但し ほとんどのクロックがクロックが停止してしまいますが、
スリープ中でも動作させることができるクロックとして、SOSCがあります。 スリープモードでSOSCを使った制御をおこなった場合 WDTがタイムアウトしても リセットがかからずウェークするだけとなり
通常の場合とWDTの挙動と異なります。 WDTがタイムタイムアウトした場合にPICをリセットするには RCONレジスタのTOフラグ( WDT
timeout Flag)をチェックしてリセットします。
<試作品仕様>
・タイマ1のクロック源は、通常モードでは外付けOSC1 また スリープモードではSOCSとする。
・プログラム起動開始時、 LED(RG2:リセット確認用)を1回点滅させること。
・タイムアウト時間4秒のWDTの動作を開始させる。
・起動後は、通常モードで LED(RG3)を繰り返し点滅させること。
・WDTは点滅サイクルの中でクリアする。 通常モードの場合はLED(RG1)を点灯させること。
・ボタンスイッチ(SW1)を押すと、通常モードの場合はタイマ1のクロック源を OSC1からSOCSに切り替え、スリープモードに移行する。LED(RG1)は消灯すること。
・スリープモードにおいて ボタンスイッチ(SW1)を押すと、ウェイクすること。
・スリープモードにおいては タイマ1の割り込みが1秒毎にかかり これによりウェイクして、WDTをクリアし、またLED(RJ0)を1回点滅させた後、再びスリープすること。
・WDTのタイムアウトが発生した場合は リセットが発生すること。
<試作品回路図>(→回路図のPDFファイル)
PIC18F87K90をつかった場合の回路図を以下に示します。

<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

<プログラム例>
#include <p18f87K90.h>
#include <stdio.h>
#include <delays.h>
#include <portb.h>
#pragma config FOSC = XT
#pragma config XINST = OFF
#pragma config WDTEN = ON
#pragma config WDTPS = 1024 //postscalor 1/1024 → 4mse x 1024 = 4096msec //timeout
int Flag_Sleep = 0; //0: Normal mode 1: Sleep mode
void int0_RB0(void);
void Interval(void);
void total_INT(void);
void delay_ms(long int cycle) //msec delay //OSC1モード
{
unsigned long int i = 0;
for (i = 0; i < cycle; i++)Delay10TCYx(20);
}
#pragma code low_vector=0x08 //割込み
void low_interrupt (void)
{
_asm goto total_INT _endasm
}
#pragma code
#pragma interruptlow total_INT
void total_INT()
{
if(INTCONbits.INT0IF == 1)int0_RB0(); //INT0(RB0)外部割込みの場合
if(PIR1bits.TMR1IF == 1)Interval(); //タイマ1の割り込みの場合
}
void int0_RB0() // 外部割込み関数
{
INTCONbits.INT0IF = 0; //変化割込みのフラグをリセット
ClrWdt(); //WDT クリア
if(PORTBbits.RB0 == 0) //RB0ポートをチェックして0なら//ボタンスイッチSW1が押された場合
{
if(Flag_Sleep == 0) //通常モードの場合
{
Flag_Sleep = 1; //スリープモードへ
T1CONbits.TMR1CS1 = 1; //b7:SOSC
T1CONbits.TMR1CS0 = 0; //b6:
T1CONbits.T1CKPS1 = 0; //b5: prescalor 1/1
T1CONbits.T1CKPS0 = 0; //b4:
T1CONbits.SOSCEN = 1; //b3: SOSC: enable
// T1CONbits.T1SYNC = 1; //b2: Do not synchronize the external clock input
T1CONbits.RD16 = 1; //b1: Read/Write mode: 16bit
T1CONbits.TMR1ON = 1; //b0: Timer1 ON
T1CON = 0b10001111; //SOSC モード //32.768KHz
LATGbits.LATG1 = 1; //LED OFF
}
else //スリープモードの場合
{
Flag_Sleep = 0; //通常モードへ
T1CON = 0b00000011; //OSC1 モード(FOSC/4) //1MHzモード
LATGbits.LATG1 = 0; //LED ON
}
}
}
void Interval()
{
PIR1bits.TMR1IF = 0; //flag clear
WriteTimer1(0x7FFE); //31μsec x (0xFFFF - 0x7FFE) = 31 x (65536-32766)
//= 1sec
if(Flag_Sleep == 1) //スリープモードの場合
{
ClrWdt(); // WDT clear //ClrWdt()がなくともリセットは発生しない
//タイマ割りこみがないとリセットは発生する。 ウェイクでWDTがクリアされる?
LATJbits.LATJ0 = 0; // LED ON
delay_ms(100);
LATJbits.LATJ0 = 1; //LED OFF
}
}
void main (void)
{
TRISBbits.TRISB0 = 1; // INT0 SW
TRISJ = 0;
TRISG = 0;
T1CONbits.TMR1CS1 = 0; //b7: FOSC/4 :Timer1 clock source is the instruction clock
T1CONbits.TMR1CS0 = 0; //b6:
T1CONbits.T1CKPS1 = 0; //b5: prescalor 1/1
T1CONbits.T1CKPS0 = 0; //b4:
T1CONbits.SOSCEN = 0; //b3: SOSC: disable
// T1CONbits.T1SYNC = 0; //b2:
T1CONbits.RD16 = 1; //b1: Read/Write mode: 16bit
T1CONbits.TMR1ON = 1; //b0: Timer1 ON
T1CON = 0b00000011; //OSC1 モード(FOSC/4) //1MHzモード
Flag_Sleep = 0; //通常モード
LATGbits.LATG1 = 0; //モード表示LED ON
LATGbits.LATG3 = 1;
LATGbits.LATG2 = 1;
delay_ms(200);
LATGbits.LATG2 = 0; //LED ON リセット確認用
delay_ms(200);
LATGbits.LATG2 = 1;
delay_ms(200);
INTCON2bits.INTEDG0 = 0; //INT0外部割込み: 立下りエッジ
WDTCONbits.SWDTEN = 1; //WDT on
//割り込み許可
RCONbits.IPEN = 0; //割り込み優先順位なし
PIE1bits.TMR1IE = 1; // Timer innterrupt enable
INTCONbits.INT0IE= 1; //INT0外部割込みの許可
INTCONbits.PEIE =1;
INTCONbits.GIE = 1;
while (1)
{
if(Flag_Sleep == 0) // 通常モード
{
LATGbits.LATG3 = 0; //LED ON
delay_ms(500);
LATGbits.LATG3 = 1; //LED OFF
delay_ms(500);
ClrWdt(); // WDT clear
}
else //Sleep モードの場合
{
Sleep();
if(RCONbits.TO == 0)Reset(); // TO: WDT timeout Flag
}
}
}
<動作結果>
| ・通常モードでLEDが点滅している時の RG3ポートの電圧波形です。 | ![]() |
| ・スリープモードで SOSCをクロック源とするタイマ1の割り込みで ウェイクしてLEDが点滅している時の RJ0ポートの電圧波形です。 |
![]() |
<追記> 実際にWDTをスリープモードで使用した場合の消費電流について検討してみました。
上記構成に対して下記の変更を実施してスリープ電流を観測しました。
@ ウェイク確認用LEDを非動作とする。
A 空きポートは出力モードとし、0vを出力する
<プログラム例>
#include <p18f87K90.h>
#include <stdio.h>
#include <delays.h>
#include <portb.h>
#pragma config FOSC = XT
#pragma config XINST = OFF
#pragma config WDTEN = ON
#pragma config WDTPS = 1024 //postscalor 1/1024 → 4mse x 1024 = 4096msec //timeout
int Flag_Sleep = 0; //0: Normal mode 1: Sleep mode
void int0_RB0(void);
void Interval(void);
void total_INT(void);
void delay_ms(long int cycle) //msec delay //OSC1モード
{
unsigned long int i = 0;
for (i = 0; i < cycle; i++)Delay10TCYx(20);
}
#pragma code low_vector=0x08 //割込み
void low_interrupt (void)
{
_asm goto total_INT _endasm
}
#pragma code
#pragma interruptlow total_INT
void total_INT()
{
if(INTCONbits.INT0IF == 1)int0_RB0(); //INT0(RB0)外部割込みの場合
if(PIR1bits.TMR1IF == 1)Interval(); //タイマ1の割り込みの場合
}
void int0_RB0() // 外部割込み関数
{
INTCONbits.INT0IF = 0; //変化割込みのフラグをリセット
ClrWdt(); //WDT クリア
if(PORTBbits.RB0 == 0) //RB0ポートをチェックして0なら//ボタンスイッチSW1が押された場合
{
if(Flag_Sleep == 0) //通常モードの場合
{
Flag_Sleep = 1; //スリープモードへ
T1CONbits.TMR1CS1 = 1; //b7:SOSC
T1CONbits.TMR1CS0 = 0; //b6:
T1CONbits.T1CKPS1 = 0; //b5: prescalor 1/1
T1CONbits.T1CKPS0 = 0; //b4:
T1CONbits.SOSCEN = 1; //b3: SOSC: enable
// T1CONbits.T1SYNC = 1; //b2: Do not synchronize the external clock input
T1CONbits.RD16 = 1; //b1: Read/Write mode: 16bit
T1CONbits.TMR1ON = 1; //b0: Timer1 ON
T1CON = 0b10001111; //SOSC モード //32.768KHz
LATGbits.LATG1 = 1; //LED OFF
}
else //スリープモードの場合
{
Flag_Sleep = 0; //通常モードへ
T1CON = 0b00000011; //OSC1 モード(FOSC/4) //1MHzモード
LATGbits.LATG1 = 0; //LED ON
}
}
}
void Interval()
{
PIR1bits.TMR1IF = 0; //flag clear
WriteTimer1(0x7FFE); //31μsec x (0xFFFF - 0x7FFE) = 31 x (65536-32766)
//= 1sec
if(Flag_Sleep == 1) //スリープモードの場合
{
ClrWdt(); // WDT clear //ClrWdt()がなくともリセットは発生しない
//タイマ割りこみがないとリセットは発生する。 ウェイクでWDTがクリアされる?
// LATJbits.LATJ0 = 0; // LED ON
// delay_ms(100);
// LATJbits.LATJ0 = 1; //LED OFF
}
}
void main (void)
{
TRISBbits.TRISB0 = 1; // INT0 SW
TRISJ = 0;
TRISG = 0;
TRISA = 0;
TRISB = 0;
TRISBbits.TRISB0 = 1; //RB0/INT0 input Mode
TRISC = 0;
TRISD = 0;
TRISE = 0;
TRISF = 0;
TRISG = 0;
TRISH = 0;
TRISJ = 0;
LATA = 0;
LATBbits.LATB1 = 0;
LATBbits.LATB2 = 0;
LATBbits.LATB3 = 0;
LATBbits.LATB4 = 0;
LATBbits.LATB5 = 0;
LATBbits.LATB6 = 0;
LATBbits.LATB7 = 0;
LATC = 0;
LATD = 0;
LATE = 0;
LATF = 0;
LATG = 0;
LATGbits.LATG1 = 1;
LATGbits.LATG2 = 1;
LATGbits.LATG3 = 1;
LATH = 0;
LATJ = 0;
LATJbits.LATJ0 = 1;
T1CONbits.TMR1CS1 = 0; //b7: FOSC/4 :Timer1 clock source is the instruction clock
T1CONbits.TMR1CS0 = 0; //b6:
T1CONbits.T1CKPS1 = 0; //b5: prescalor 1/1
T1CONbits.T1CKPS0 = 0; //b4:
T1CONbits.SOSCEN = 0; //b3: SOSC: disable
// T1CONbits.T1SYNC = 0; //b2:
T1CONbits.RD16 = 1; //b1: Read/Write mode: 16bit
T1CONbits.TMR1ON = 1; //b0: Timer1 ON
T1CON = 0b00000011; //OSC1 モード(FOSC/4) //1MHzモード
Flag_Sleep = 0; //通常モード
LATGbits.LATG1 = 0; //モード表示LED ON
LATGbits.LATG3 = 1;
LATGbits.LATG2 = 1;
delay_ms(200);
LATGbits.LATG2 = 0; //LED ON リセット確認用
delay_ms(200);
LATGbits.LATG2 = 1;
delay_ms(200);
INTCON2bits.INTEDG0 = 0; //INT0外部割込み: 立下りエッジ
WDTCONbits.SWDTEN = 1; //WDT on
//割り込み許可
RCONbits.IPEN = 0; //割り込み優先順位なし
PIE1bits.TMR1IE = 1; // Timer innterrupt enable
INTCONbits.INT0IE= 1; //INT0外部割込みの許可
INTCONbits.PEIE =1;
INTCONbits.GIE = 1;
while (1)
{
if(Flag_Sleep == 0) // 通常モード
{
LATGbits.LATG3 = 0; //LED ON
delay_ms(500);
LATGbits.LATG3 = 1; //LED OFF
delay_ms(500);
ClrWdt(); // WDT clear
}
else //Sleep モードの場合
{
Sleep();
if(RCONbits.TO == 0)Reset(); // TO: WDT timeout Flag
}
}
}
<追記の実験結果>
・ Sleep中の電流は1.9μA程度である。ウェイクした時の電流(波高値)は(推定)20μA以下である。
